package clids.ex1.analysis;

import java.util.LinkedList;
import java.util.TreeSet;
import clids.ex1.data_structures.MyHashSet;

import java.util.Date; 

/**
 * A class that compares performance of 3 data structures - LinkedList, TreeSet and MyHashSet,
 * measuring time required to perform some of their operations.
 * 
 * Consists of the main method, and several static methods, that are used 
 * for different operations time analysis.
 * 
 * @author Ori Miller 
 *
 */
public class MyAnalysis {
	
	/**
	 * Measures the time needed to add strings from given array 
	 * into a given LinkedList data structure.
	 * At the end, the LinkedList will contain the added words.
	 * 
	 * @param wordsToAdd array of words to be added into LinkedList.
	 * @param lst LinkedList to which words will be added.
	 * 
	 * @return time in milliseconds that needed to perform adding of all words.
	 * 
	 */
	public static long addWordsToListTime(String[] wordsToAdd, LinkedList<String> lst) {

		long timeBefore = new Date().getTime();

		for (int i = 0; i < wordsToAdd.length; i++) {

			lst.add(wordsToAdd[i]);
		}

		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);
	}
	
	
	/**
	 * Measures the time needed to add strings from given array 
	 * into a given TreeSet data structure.
	 * At the end, the TreeSet will contain the added words.
	 * 
	 * @param wordsToAdd array of words to be added into TreeSet.
	 * @param tree TreeSet to which words will be added.
	 * 
	 * @return time in milliseconds that needed to perform adding of all words.
	 * 
	 */
	public static long addWordsToTreeTime(String[] wordsToAdd, TreeSet<String> tree) {

		long timeBefore = new Date().getTime();

		for (int i = 0; i < wordsToAdd.length; i++) {

			tree.add(wordsToAdd[i]);
		}

		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);
	}
	
	
	/**
	 * Measures the time needed to add strings from given array 
	 * into a given MyHashSet data structure.
	 * At the end, the MyHashSet will contain the added words.
	 * 
	 * @param wordsToAdd array of words to be added into MyHashSet.
	 * @param hashSet MyHashSet to which words will be added.
	 * 
	 * @return time in milliseconds that needed to perform adding of all words.
	 * 
	 */
	public static long addWordsToHashSetTime(String[] wordsToAdd, MyHashSet hashSet) {

		long timeBefore = new Date().getTime();

		for (int i = 0; i < wordsToAdd.length; i++) {

			hashSet.add(wordsToAdd[i]);
		}

		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);
	}
	
	/**
	 * Measures the time needed to perform contains operation 
	 * of given string in given LinkedList data structure.
	 * 
	 * @param toSearch a string to search in LinkedList.
	 * @param lst LinkedList to search in.
	 * 
	 * @return time in milliseconds that needed to perform contains operation.
	 * 
	 */
	public static long containsList(String toSearch, LinkedList<String> lst) {
		
		long timeBefore = new Date().getTime();
		lst.contains(toSearch);
		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);
	}
	
	/**
	 * Measures the time needed to perform contains operation 
	 * of given string in given TreeSet data structure.
	 * 
	 * @param toSearch a string to search in TreeSet.
	 * @param tree TreeSet to search in.
	 * 
	 * @return time in milliseconds that needed to perform contains operation.
	 * 
	 */
	public static long containsTree(String toSearch, TreeSet<String> tree) {
		
		long timeBefore = new Date().getTime();
		tree.contains(toSearch);
		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);
	}
	
	/**
	 * Measures the time needed to perform contains operation 
	 * of given string in given MyHashSet data structure.
	 * 
	 * @param toSearch a string to search in MyHashSet.
	 * @param hashSet MyHashSet to search in.
	 * 
	 * @return time in milliseconds that needed to perform contains operation.
	 * 
	 */
	public static long containsHS(String toSearch, MyHashSet hashSet) {

		long timeBefore = new Date().getTime();
		hashSet.contains(toSearch);
		long timeAfter = new Date().getTime();

		return (timeAfter - timeBefore);	
	}

	/** 
     * The main method. 
     * 
     * Performs various operations on 3 data structures - LinkedList, TreeSet and MyHashSet,
     * and prints the times required for them, with appropriate messages.
     * 
     * @param args command-line arguments array:
     * 		  - the first argument should be path to data1.txt file.
     * 		  - the second argument should be path to data2.txt file.
     * 
     */
	public static void main(String[] args) {

		String[] data1Words = Ex1Utils.file2array(args[0]);
		String[] data2Words = Ex1Utils.file2array(args[1]);
		
		//the 3 data structures we will analyze.
		TreeSet<String> tree = new TreeSet<String>();
		LinkedList<String> list = new LinkedList<String>();
		MyHashSet hashSet = new MyHashSet();

		/*
		 * analysis on data1 file.
		 * 
		 */
		
		//analysis of add operation (section 6.b.1).
		long timeRequired = addWordsToListTime(data1Words, list);
		System.out.println("Time required to add data1 into LinkedList: " + timeRequired);
		
		timeRequired = addWordsToTreeTime(data1Words, tree);
		System.out.println("Time required to add data1 into TreeSet: " + timeRequired);
		
		timeRequired = addWordsToHashSetTime(data1Words, hashSet);
		System.out.println("Time required to add data1 into MyHashSet: " + timeRequired);
		
		//analysis of contains operation (section 6.b.2).
		//list, tree and hashSet contain words of data1 at this point.
		String s1 = "hi";
		String s2 = "-13170890158";
	
		//contains of "hi".
		System.out.println("Time for contains check in LinkedList (data1) for 'hi': " + containsList(s1, list));
		
		System.out.println("Time for contains check in TreeSet (data1) for 'hi': " + containsTree(s1, tree));
		
		System.out.println("Time for contains check in MyHashSet (data1) for 'hi': " + containsHS(s1, hashSet));
		
		//contains of "-13170890158".
		System.out.println("Time for contains check in LinkedList (data1) for '-13170890158': " + containsList(s2, list));
		
		System.out.println("Time for contains check in TreeSet (data1) for '-13170890158': " + containsTree(s2, tree));
		
		System.out.println("Time for contains check in MyHashSet (data1) for '-13170890158': " + containsHS(s2, hashSet));
		
		
		//cleaning data structures.
		tree = new TreeSet<String>();
		list = new LinkedList<String>();
		hashSet = new MyHashSet();
		
		/*
		 * analysis on data2 file.
		 * 
		 */
		
		//analysis of add operation (section 6.b.1).
		timeRequired = addWordsToListTime(data2Words, list);
		System.out.println("Time required to add data2 into LinkedList: " + timeRequired);
		
		timeRequired = addWordsToTreeTime(data2Words, tree);
		System.out.println("Time required to add data2 into TreeSet: " + timeRequired);
		
		timeRequired = addWordsToHashSetTime(data2Words, hashSet);
		System.out.println("Time required to add data2 into MyHashSet: " + timeRequired);
		
		//analysis of contains operation (section 6.b.3).
		//list, tree and hashSet contain words of data2 at this point.
		String s3 = "23";
	
		//contains of "hi".
		System.out.println("Time for contains check in LinkedList (data2) for 'hi': " + containsList(s1, list));
		
		System.out.println("Time for contains check in TreeSet (data2) for 'hi': " + containsTree(s1, tree));
		
		System.out.println("Time for contains check in MyHashSet (data2) for 'hi': " + containsHS(s1, hashSet));
		
		//contains of "23".
		System.out.println("Time for contains check in LinkedList (data2) for '23': " + containsList(s3, list));
		
		System.out.println("Time for contains check in TreeSet (data2) for '23': " + containsTree(s3, tree));
		
		System.out.println("Time for contains check in MyHashSet (data2) for '23': " + containsHS(s3, hashSet));
		
		
	} //end of main.

} //end of class.
